package easier.data.store;

import android.content.Context;
import androidx.collection.ArraySet;
import androidx.datastore.preferences.core.MutablePreferences;
import androidx.datastore.preferences.core.Preferences;
import androidx.datastore.preferences.core.Preferences.Key;
import androidx.datastore.preferences.core.PreferencesKeys;
import androidx.datastore.preferences.rxjava3.RxPreferenceDataStoreBuilder;
import androidx.datastore.rxjava3.RxDataStore;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.functions.Function;
import java.util.Set;

public class RxPreferencesStoreManager {

    private final RxDataStore< Preferences > dataStore;
    private final Flowable< Preferences > mData;

    public RxPreferencesStoreManager( Context context, String name ) {

        dataStore = new RxPreferenceDataStoreBuilder( context, name ).build();
        mData = dataStore.data();
    }

    public Flowable< Integer > observeInt( String key ) {

        Key< Integer > integerKey = PreferencesKeys.intKey( key );
        return mData.map( new Function< Preferences, Integer >() {
            @Override
            public Integer apply( Preferences preferences ) throws Throwable {

                Integer integer = preferences.get( integerKey );
                return integer == null ? 0 : integer;
            }
        } );
    }

    public Flowable< Double > observeDouble( String key ) {

        Key< Double > integerKey = PreferencesKeys.doubleKey( key );
        return mData.map( new Function< Preferences, Double >() {
            @Override
            public Double apply( Preferences preferences ) throws Throwable {

                Double value = preferences.get( integerKey );
                return value == null ? 0 : value;
            }
        } );
    }

    public Flowable< Float > observeFloat( String key ) {

        Key< Float > integerKey = PreferencesKeys.floatKey( key );
        return mData.map( new Function< Preferences, Float >() {
            @Override
            public Float apply( Preferences preferences ) throws Throwable {

                Float value = preferences.get( integerKey );
                return value == null ? 0 : value;
            }
        } );
    }

    public Flowable< Long > observeLong( String key ) {

        Key< Long > integerKey = PreferencesKeys.longKey( key );
        return mData.map( new Function< Preferences, Long >() {
            @Override
            public Long apply( Preferences preferences ) throws Throwable {

                Long value = preferences.get( integerKey );
                return value == null ? 0 : value;
            }
        } );
    }

    public Flowable< Boolean > observeBoolean( String key, boolean defaultValue ) {

        Key< Boolean > integerKey = PreferencesKeys.booleanKey( key );
        return mData.map( new Function< Preferences, Boolean >() {
            @Override
            public Boolean apply( Preferences preferences ) throws Throwable {

                Boolean value = preferences.get( integerKey );
                return value == null ? defaultValue : value;
            }
        } );
    }

    public Flowable< String > observeString( String key ) {

        Key< String > integerKey = PreferencesKeys.stringKey( key );
        return mData.map( new Function< Preferences, String >() {
            @Override
            public String apply( Preferences preferences ) throws Throwable {

                String value = preferences.get( integerKey );
                return value == null ? "" : value;
            }
        } );
    }

    public Flowable< Set< String > > observeStringSet( String key ) {

        Key< Set< String > > integerKey = PreferencesKeys.stringSetKey( key );
        return mData.map( new Function< Preferences, Set< String > >() {
            @Override
            public Set< String > apply( Preferences preferences ) throws Throwable {

                Set< String > value = preferences.get( integerKey );
                return value == null ? new ArraySet<>() : value;
            }
        } );
    }

    public void updateData( String key, int value ) {

        dataStore.updateDataAsync( new Function< Preferences, Single< Preferences > >() {
            @Override
            public Single< Preferences > apply( Preferences preferences ) throws Throwable {

                Key< Integer > intentKey = PreferencesKeys.intKey( key );
                MutablePreferences mutablePreferences = preferences.toMutablePreferences();
                mutablePreferences.set( intentKey, value );
                return Single.just( mutablePreferences );
            }
        } );
    }

    public void updateData( String key, double value ) {

        dataStore.updateDataAsync( new Function< Preferences, Single< Preferences > >() {
            @Override
            public Single< Preferences > apply( Preferences preferences ) throws Throwable {

                Key< Double > intentKey = PreferencesKeys.doubleKey( key );
                MutablePreferences mutablePreferences = preferences.toMutablePreferences();
                mutablePreferences.set( intentKey, value );
                return Single.just( mutablePreferences );
            }
        } );
    }

    public void updateData( String key, long value ) {

        dataStore.updateDataAsync( new Function< Preferences, Single< Preferences > >() {
            @Override
            public Single< Preferences > apply( Preferences preferences ) throws Throwable {

                Key< Long > intentKey = PreferencesKeys.longKey( key );
                MutablePreferences mutablePreferences = preferences.toMutablePreferences();
                mutablePreferences.set( intentKey, value );
                return Single.just( mutablePreferences );
            }
        } );
    }

    public void updateData( String key, float value ) {

        dataStore.updateDataAsync( new Function< Preferences, Single< Preferences > >() {
            @Override
            public Single< Preferences > apply( Preferences preferences ) throws Throwable {

                Key< Float > intentKey = PreferencesKeys.floatKey( key );
                MutablePreferences mutablePreferences = preferences.toMutablePreferences();
                mutablePreferences.set( intentKey, value );
                return Single.just( mutablePreferences );
            }
        } );
    }

    public void updateData( String key, boolean value ) {

        dataStore.updateDataAsync( new Function< Preferences, Single< Preferences > >() {
            @Override
            public Single< Preferences > apply( Preferences preferences ) throws Throwable {

                Key< Boolean > intentKey = PreferencesKeys.booleanKey( key );
                MutablePreferences mutablePreferences = preferences.toMutablePreferences();
                mutablePreferences.set( intentKey, value );
                return Single.just( mutablePreferences );
            }
        } );
    }

    public void updateData( String key, String value ) {

        dataStore.updateDataAsync( new Function< Preferences, Single< Preferences > >() {
            @Override
            public Single< Preferences > apply( Preferences preferences ) throws Throwable {

                Key< String > intentKey = PreferencesKeys.stringKey( key );
                MutablePreferences mutablePreferences = preferences.toMutablePreferences();
                mutablePreferences.set( intentKey, value );
                return Single.just( mutablePreferences );
            }
        } );
    }

    public void updateData( String key, Set< String > value ) {

        dataStore.updateDataAsync( new Function< Preferences, Single< Preferences > >() {
            @Override
            public Single< Preferences > apply( Preferences preferences ) throws Throwable {

                Key< Set< String > > intentKey = PreferencesKeys.stringSetKey( key );
                MutablePreferences mutablePreferences = preferences.toMutablePreferences();
                mutablePreferences.set( intentKey, value );
                return Single.just( mutablePreferences );
            }
        } );
    }

    public void dispose() {

        dataStore.dispose();
        /* 必须等待完成才能继续 */
        dataStore.shutdownComplete().blockingAwait();
    }
}